import * as MathUtils from '../math/MathUtils.js';
import { StaticDrawUsage } from '../constants.js';

class InterleavedBuffer {
  constructor(array, stride) {
    this.array = array;
    this.stride = stride;
    this.count = array !== undefined ? array.length / stride : 0;

    this.usage = StaticDrawUsage;
    this.updateRange = { offset: 0, count: -1 };

    this.version = 0;

    this.uuid = MathUtils.generateUUID();
  }

  onUploadCallback() {}

  set needsUpdate(value) {
    if (value === true) this.version++;
  }

  setUsage(value) {
    this.usage = value;

    return this;
  }

  copy(source) {
    this.array = new source.array.constructor(source.array);
    this.count = source.count;
    this.stride = source.stride;
    this.usage = source.usage;

    return this;
  }

  copyAt(index1, attribute, index2) {
    index1 *= this.stride;
    index2 *= attribute.stride;

    for (let i = 0, l = this.stride; i < l; i++) {
      this.array[index1 + i] = attribute.array[index2 + i];
    }

    return this;
  }

  set(value, offset = 0) {
    this.array.set(value, offset);

    return this;
  }

  clone(data) {
    if (data.arrayBuffers === undefined) {
      data.arrayBuffers = {};
    }

    if (this.array.buffer._uuid === undefined) {
      this.array.buffer._uuid = MathUtils.generateUUID();
    }

    if (data.arrayBuffers[this.array.buffer._uuid] === undefined) {
      data.arrayBuffers[this.array.buffer._uuid] = this.array.slice(0).buffer;
    }

    const array = new this.array.constructor(data.arrayBuffers[this.array.buffer._uuid]);

    const ib = new this.constructor(array, this.stride);
    ib.setUsage(this.usage);

    return ib;
  }

  onUpload(callback) {
    this.onUploadCallback = callback;

    return this;
  }

  toJSON(data) {
    if (data.arrayBuffers === undefined) {
      data.arrayBuffers = {};
    }

    // generate UUID for array buffer if necessary

    if (this.array.buffer._uuid === undefined) {
      this.array.buffer._uuid = MathUtils.generateUUID();
    }

    if (data.arrayBuffers[this.array.buffer._uuid] === undefined) {
      data.arrayBuffers[this.array.buffer._uuid] = Array.prototype.slice.call(new Uint32Array(this.array.buffer));
    }

    //

    return {
      uuid: this.uuid,
      buffer: this.array.buffer._uuid,
      type: this.array.constructor.name,
      stride: this.stride,
    };
  }
}

InterleavedBuffer.prototype.isInterleavedBuffer = true;

export { InterleavedBuffer };
